// Copyright 2021 Guoyoko. All Rights Reserved.

#include "CustomizeFlowEditor.h"
#include "Node/CustomizeFlow_BlueprintBase.h"
#include "Graph/CustomizeFlowGraphTypes.h"
#include "Commands/CustomizeFlowCommands.h"
#include "ToolMenus.h"
#include "Subsystem/FlowWorldSubsystem.h"
#include "Toolkits/CustomizeFlowEditorToolkit.h"


#define LOCTEXT_NAMESPACE "FCustomizeFlowModuleEditor"

void FCustomizeFlowEditorModule::StartupModule()
{
	// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module

	IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
	RegisterAssetAction(AssetTools, MakeShareable(new FCustomizeFlowActions));


	FCusFEditorCommands::Register();
	BindCommands();
	UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FCustomizeFlowEditorModule::RegisterMenus));
}

void FCustomizeFlowEditorModule::ShutdownModule()
{
	// This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,
	// we call this function before unloading the module.

	UnRegisterAssetActions();
}

void FCustomizeFlowEditorModule::RegisterAssetAction(class IAssetTools& AssetTools, TSharedRef<class IAssetTypeActions> Action)
{
	AssetTools.RegisterAssetTypeActions(Action);
	RegisteredAssetTypeActions.Add(Action);
}

void FCustomizeFlowEditorModule::UnRegisterAssetActions()
{
	FAssetToolsModule* AssetToolsModule = FModuleManager::GetModulePtr<FAssetToolsModule>("AssetTools");

	if (AssetToolsModule != nullptr)
	{
		IAssetTools& AssetTools = AssetToolsModule->Get();

		for (auto Action : RegisteredAssetTypeActions)
		{
			AssetTools.UnregisterAssetTypeActions(Action);
		}
	}
}

void FCustomizeFlowEditorModule::BindCommands()
{
	CusFEditorCommands = MakeShareable(new FUICommandList);
	CusFEditorCommands->MapAction(
		FCusFEditorCommands::Get().OpenCustomizeFlowEditor,
		FExecuteAction::CreateRaw(this, &FCustomizeFlowEditorModule::OpenEditorForCusFAsset),
		FCanExecuteAction()
	);
}

void FCustomizeFlowEditorModule::RegisterMenus()
{
	UToolMenu* ToolbarMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.LevelEditorToolBar");

	FToolMenuSection& Section = ToolbarMenu->FindOrAddSection("Settings");

	FToolMenuEntry& Entry = Section.AddEntry(FToolMenuEntry::InitToolBarButton(FCusFEditorCommands::Get().OpenCustomizeFlowEditor));
	Entry.SetCommandList(CusFEditorCommands);
}

void FCustomizeFlowEditorModule::OpenEditorForCusFAsset()
{
	UWorld* World = GetWorld();
	if (World == nullptr)
	{
		return;
	}

	UCustomizeFlowAsset* CusFlowAssetObj = World->GetSubsystem<UFlowWorldSubsystem>()->GetCurrentLevelCusFlowAssetObj();
	if (CusFlowAssetObj)
	{
		if ((GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->FindEditorForAsset(CusFlowAssetObj, true) == nullptr))
		{
			CreateClassCache();

			EToolkitMode::Type Mode = EToolkitMode::Standalone;
			TSharedPtr<IToolkitHost> EditWithinLevelEditor = TSharedPtr<IToolkitHost>();
			TSharedRef<FCustomizeFlowEditorToolkit> EditorToolkit(new FCustomizeFlowEditorToolkit());
			EditorToolkit->Initialize(Mode, EditWithinLevelEditor, CusFlowAssetObj);
		}
	}
}

UWorld* FCustomizeFlowEditorModule::GetWorld(UObject* OptionalObject /*= nullptr*/)
{
	UWorld* World = GEngine->GetWorldFromContextObject(OptionalObject, EGetWorldErrorMode::ReturnNull);
#if WITH_EDITOR
	if (!World && GIsEditor)
	{
		UEditorEngine* EEngine = Cast<UEditorEngine>(GEngine);
		// lets use PlayWorld during PIE/Simulate and regular world from editor otherwise, to draw debug information
		World = EEngine != nullptr && EEngine->PlayWorld != nullptr ? EEngine->PlayWorld : EEngine->GetEditorWorldContext().World();
	}
	else
#endif
		if (!World && !GIsEditor)
		{
			World = GEngine->GetWorld();
		}

	if (World == nullptr)
	{
		World = GWorld;
	}

	return World;
}

void FCustomizeFlowEditorModule::CreateClassCache()
{
	if (!ClassCache.IsValid())
	{
		ClassCache = MakeShareable(new FCusFlowGraphNodeClassHelper(UCustomizeFlowNode::StaticClass()));
		FCusFlowGraphNodeClassHelper::AddObservedBlueprintClasses(UCustomizeFlow_BlueprintBase::StaticClass());

		ClassCache->UpdateAvailableBlueprintClasses();
	}
}

#undef LOCTEXT_NAMESPACE
	
IMPLEMENT_MODULE(FCustomizeFlowEditorModule, CustomizeFlowEditor)